Return to Homepage

Introduction

In the following report, I will investigate and examine which animal is the king of attacks whether on land or in the water, by comparing the attacks from sharks, wolves, and alligators. While this data has already been somewhat cleaned and contains fairly simple information, this final project aims to investigate the disparities between these three animals, the attack locations, and the effected population. In simpler terms, who is responsible for the most attacks? Which populations are the most effected? Were these attacks provoked or not? These are just some of the questions I hope to explore in this writing.

Background

This project was inspired in part by my family, my mother is from Florida and there have been some very interesting documentaries done on all these animals. It was also inspired by general happen stance: I found a very nice data set on Kaggle and felt it could be an interesting take on a seemingly dull data set. As mentioned, this data set was found:

Fatal Alligator Attacks

Shark Attacks

Shark Attacks By Hemispheres

Global Wolf Attacks

The data set consists of various reported statistics regarding these different attacks. Most types of attacks were not only predatory, but unprovoked. However, some individuals were reported to provoke the animal. Different age groups were attacked each time.

Prevention would be great, but there are not signs for those that will and could be attacked. Alligators, sharks, and wolves have different reasons to attack.

Data

# load all necessary libraries 
library(tidyverse)
library(janitor)
library(leaflet)
library(dplyr)
library(ggplot2)
library(lubridate)
library(stringr)
library(readr)

# reading in kaggle data sets 
gator <- read.csv("predators/fatal_alligator_attacks_US.csv")

g_wolves <- read.csv("predators/global_wolves.csv")

shark_1 <- read.csv("predators/Shark_attacks/attacks.csv")

shark_2 <- read.csv("predators/shark_attacks.csv")

shark_3 <- read.csv("predators/Shark_attacks/list_coor_australia.csv")

This data set was retrieved from Kaggle and has already been somewhat cleaned for analysis. However, there are some changes I wanted to make to the data structure, changing missing values/empty spaces, cleaning the names, and improving characters found throughout the data set. The following code and outputs demonstrate the changes I’ve made to allow for smoother data analysis:

# convert column titles to snake_case 

gator <-clean_names(gator)

g_wolves <-clean_names(g_wolves)

shark_1 <- clean_names(shark_1)

shark_2 <-clean_names(shark_2)
# converts all N/A chr values to actual missing values and fills in empty spaces with missing values 

g_wolves$type_of_attack[is.na(g_wolves$type_of_attack) | g_wolves$type_of_attack == ""] <- "Unknown"

shark_2$type[is.na(shark_2$type) | shark_2$type == "Invalid"] <- "Unknown"

shark_1 <- shark_1[!is.na(shark_1$type), ] 
shark_1_subset <- shark_1[1:6302, ]
nrow(shark_1)
## [1] 25723
length(shark_1$type)
## [1] 25723
# Check which rows have NA or invalid values
table(is.na(shark_1$type))  
## 
## FALSE 
## 25723
table(shark_1$type == "Invalid")  
## 
## FALSE  TRUE 
## 25176   547
# Replace only NAs first, then Invalids
shark_1$type[is.na(shark_1$type)] <- "Unknown"
shark_1$type[shark_1$type == "Invalid"] <- "Unknown"


# converts data structure to more appropriate data types
gator <-gator %>% 
  mutate(location = str_extract(details, "(Miami|Florida|Georgia|Texas|Louisiana|South Carolina)"),
         location = ifelse(location == "Miami", "Florida", location))

Alligator

knitr::include_graphics("media/gator.png")

Picture came from TreeHugger

Alligators are beautiful and dangerous animals. This data only shows a small amount of deaths that have been caused by alligators. There was no information about crocodiles (crocs), even though they do have a hand in many deaths over the years, since invading the South. This data shows that Florida has had the most number of attacks. I have learned over the years, to keep an eye out whenever by water on the Southern coast. You never know what might snap you up.

## # A tibble: 7 × 3
## # Groups:   location [5]
##   location       sex        n
##   <chr>          <chr>  <int>
## 1 Florida        female    11
## 2 Florida        male      19
## 3 Georgia        female     1
## 4 Louisiana      male       2
## 5 South Carolina female     4
## 6 South Carolina male       1
## 7 Texas          male       3

Unexpected Shark Attacks

When I first started trying to create this plot, this was the result. Attacks happening above Greenland. I learned how wrong I was.

knitr::include_graphics("media/Unexpected_Attacks.png")

Sharks

knitr::include_graphics("media/shark.png")

Picture from britannica

If any of you have an unrealistic fear that there is something in the water and you will get attacked, you’re not alone. Look what is happening in Australia. Zoom out and see what is happening.

colnames(shark_3) <- c("latitude", "longitude")
center_lat <- -25.2744
center_lon <- 133.7751
zoom_level <- 5  

map <- leaflet() %>%
  addTiles() %>%  
  setView(center_lon, center_lat, zoom = zoom_level)

for (i in 1:nrow(shark_3)) {
  map <- map %>% addMarkers(lng = shark_3$longitude[i], lat = shark_3$latitude[i])
}

map
knitr::include_graphics("media/Australia.png")

This is what the map looks like when zoomed out. Crazy, right?

More Attacks

shark_1$type[is.na(shark_1$type) | shark_1$type == ""] <- "Unknown"
shark_1$type[is.na(shark_1$type) | shark_1$type == "Invalid"] <- "Unknown"
shark_1_subset <- shark_1[1:6302, ]

sharks <- shark_1 %>% 
  group_by(country) %>% 
  ggplot(aes(x = type)) +
  geom_bar(aes(y = ..count..)) + 
  geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 14),  
        axis.text.y = element_text(size = 14),  
        plot.title = element_text(hjust = 0.5, size = 16),  
        axis.title.x = element_text(size = 16),  
        axis.title.y = element_text(size = 16)) + 
  labs(title = "Shark Attacks by Type", 
       x = "Type of Attack", 
       y = "Count of Attacks")

# Plot the chart
plot(sharks)

Does anyone have an idea what boatomg is? I think they meant boating, but messed up on their English. It is understandable to a degree, English is hard.

More Shark Attacks

shark_2$type[is.na(shark_2$type) | shark_2$type == "Invalid"] <- "Unknown"

shark_2 %>% 
  group_by(area) %>% 
  ggplot(aes(x = type)) +
  geom_bar(aes(y = ..count..)) + 
  geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 14),  
    axis.text.y = element_text(size = 14),  
    axis.title.x = element_text(size = 16),  
    axis.title.y = element_text(size = 16)   
  ) + 
  labs(title = "Shark Attacks by Type", 
       x = "Type of Attack", 
       y = "Count of Attacks")

top_countries <- shark_2 %>%
  count(country, sort = TRUE) %>%
  top_n(15, n) %>%
  pull(country)


shark_2 %>%
  filter(country != "",country %in% top_countries) %>%
  mutate(month = month(as.Date(date, format = "%d-%B-%Y"), label = TRUE)) %>%
  filter(!is.na(month)) %>%
  group_by(country, month) %>%
  summarise(attacks = n(), .groups = "drop") %>%
  mutate(area = fct_reorder(country, attacks, .fun = sum)) %>%
  ggplot(aes(x = country, y = month)) +
  geom_point(aes(size = attacks, color = attacks), alpha = 0.7) +
  scale_size_continuous(range = c(2, 10)) +
  scale_color_gradient(low = "skyblue", high = "red") +
  labs(
    x = "Country",
    y = "Month",
    size = "Number of Attacks",
    color = "Number of Attacks",
    title = "Shark Attacks by Month"
  ) +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
  coord_flip()

USA

# List of all U.S. states
us_states <- c(
  "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", 
  "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", 
  "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", 
  "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", 
  "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", 
  "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", 
  "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", 
  "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"
)

# Now filter based on U.S. states
shark_2 %>%
  filter(country == "USA", area %in% us_states) %>%
  mutate(month = month(as.Date(date, format = "%d-%B-%Y"), label = TRUE)) %>%
  filter(!is.na(month)) %>%
  group_by(area, month) %>%
  summarise(attacks = n(), .groups = "drop") %>%
  mutate(area = fct_reorder(area, attacks, .fun = sum, .desc = TRUE)) %>%
  ggplot(aes(x = area, y = month)) +
  geom_point(aes(size = attacks, color = attacks), alpha = 0.7) +
  scale_size_continuous(range = c(2, 10)) +
  scale_color_gradient(low = "skyblue", high = "red") +
  labs(
    x = "States",
    y = "Month",
    size = "Number of Attacks",
    color = "Number of Attacks",
    title = "Shark Attacks by Month in U.S.A."
  ) +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
  coord_flip()

When Comparing: USA vs. Australia

shark_2 %>%
  filter(country %in% c("USA", "AUSTRALIA")) %>%
  mutate(month = month(as.Date(date, format = "%d-%B-%Y"), label = TRUE)) %>%
  filter(!is.na(month)) %>%
  group_by(country, month) %>%
  summarise(attacks = n(), .groups = "drop") %>%
  ggplot(aes(x = month, y = attacks)) +
  geom_point(aes(size = attacks, color = attacks), alpha = 0.7) +
  scale_size_continuous(range = c(2, 10)) +
  scale_color_gradient(low = "skyblue", high = "red") +
  labs(
    x = "Month",
    y = "Number of Attacks",
    size = "Number of Attacks",
    color = "Number of Attacks",
    title = "Monthly Shark Attacks: USA vs Australia"
  ) +
  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  facet_wrap(~ country, ncol = 1)

Wolves: Before Cleaning

knitr::include_graphics("media/wolves.png")

Picture from britannica-Wolves

g_wolves$type_of_attack[is.na(g_wolves$type_of_attack) | g_wolves$type_of_attack == ""] <- "Unknown"

wolves <- g_wolves %>% 
  group_by(type_of_attack) %>% 
  ggplot(aes(x = type_of_attack))  +
  geom_bar(aes(y = ..count..)) + 
  geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1, size = 14),  
    axis.text.y = element_text(size = 14), 
    axis.title.x = element_text(size = 16),  
    axis.title.y = element_text(size = 16)  
  ) +
  labs(x = "Types of Attacks", y = "Victim Count")

plot(wolves)

When I was looking and trying to clean the data, there were many factors that affected it. The data was not pretty even after trying to clean it. The attacks are even higher than data above. There was some data that represented 15 people that were killed by wolves. All 15 people were placed on the same line. This is how it looked before really cleaning the data.

# Read the CSV file (assuming it's saved as 'global_wolves.csv')
data <- read.csv("predators/global_wolves.csv", stringsAsFactors = FALSE)

data <- clean_names(data)

# Use a regular expression to extract the country from the 'Location' column
data$country <- sub(".*,\\s*(.*)$", "\\1", data$location)

# Extract the country from location string
data$country <- str_extract(data$location, "[^,]+$")

# Trim any leading/trailing whitespace
data$country <- trimws(data$country)

# Replace blank box with NA
data <- data %>%
  mutate(type_of_attack = ifelse(type_of_attack == "", NA, type_of_attack))

data %>% 
  ggplot(aes(x = country, fill = type_of_attack)) +
  geom_bar(position = "dodge") +
  coord_flip() + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +  
  labs(title = "Attacks and Country",
       x = "Country",
       y = "Count of Attacks") +
  theme_minimal()+
  theme(
    plot.title = element_text(hjust = 0.5),
    axis.text.y = element_text(size = 8))  

knitr::include_graphics("media/wolves_attacks.png")

Clean-ish Wolves Data

### Attempt 2
# Load the CSV
df <- read_csv("predators/global_wolves.csv") %>% 
  clean_names()

# Function to split or duplicate victims
expand_victims <- function(victim_string, row_data) {
  row_data <- as_tibble(row_data)  
  
  # Insert separator where gender is jammed with next name, like "maleAlex"
  victim_string <- str_replace_all(victim_string, "(male|female)(?=[A-Z])", "\\1; ")
  
  # Case 1: multiple named people
  if (str_detect(victim_string, "[A-Za-z]+, \\d{1,2}, (male|female)")) {
    people <- str_extract_all(victim_string, "[^,]+, \\d{1,2}, (male|female)")[[1]]
    return(map_df(people, ~ mutate(row_data, victims = .x)))
  }
  
  # Case 2: vague with number
  number_match <- str_match(victim_string, "(\\d+)|([Tt]wo|[Tt]hree|[Ff]our|[Ff]ive|[Ss]ix|[Ss]even|[Ee]ight)")
  if (!is.na(number_match[1])) {
    num <- suppressWarnings(as.numeric(number_match[1]))
    if (is.na(num)) {
      num <- case_when(
        str_detect(number_match[1], regex("two", ignore_case = TRUE)) ~ 2,
        str_detect(number_match[1], regex("three", ignore_case = TRUE)) ~ 3,
        str_detect(number_match[1], regex("four", ignore_case = TRUE)) ~ 4,
        str_detect(number_match[1], regex("five", ignore_case = TRUE)) ~ 5,
        str_detect(number_match[1], regex("six", ignore_case = TRUE)) ~ 6,
        str_detect(number_match[1], regex("seven", ignore_case = TRUE)) ~ 7,
        str_detect(number_match[1], regex("eight", ignore_case = TRUE)) ~ 8,
        str_detect(number_match[1], regex("eight", ignore_case = TRUE)) ~ 9,
        str_detect(number_match[1], regex("eight", ignore_case = TRUE)) ~ 10,
        str_detect(number_match[1], regex("eight", ignore_case = TRUE)) ~ 11,
        str_detect(number_match[1], regex("eight", ignore_case = TRUE)) ~ 12,
        str_detect(number_match[1], regex("eight", ignore_case = TRUE)) ~ 13,
        str_detect(number_match[1], regex("eight", ignore_case = TRUE)) ~ 14,
        str_detect(number_match[1], regex("eight", ignore_case = TRUE)) ~ 15,
        TRUE ~ 1
      )
    }
    return(map_df(1:num, ~ mutate(row_data, victims = "Unknown")))
  }
  
  # Default: return original row
  return(row_data)
}

# Apply to each row
cleaned_df <- df %>%
  rowwise() %>%
  do(expand_victims(.$victims, .)) %>%
  ungroup()

# First extract the country
cleaned_df <- cleaned_df %>%
  mutate(country = str_extract(location, "[^,]+$") %>% str_trim())

# Then remove any trailing periods
cleaned_df <- cleaned_df %>%
  mutate(country = str_remove(country, "\\.$"))

cleaned_df %>% 
  ggplot(aes(x = country, fill = type_of_attack)) +
  geom_bar(position = "dodge") +
  coord_flip() + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +  
  labs(title = "Attacks and Country",
       x = "Country",
       y = "Count of Attacks") +
  theme_minimal()+
  theme(
    plot.title = element_text(hjust = 0.5),
    axis.text.y = element_text(size = 8))  

knitr::include_graphics("media/Second_Attempt.png")

Cleaner Wolf Data

# Load and clean the dataset
df <- read_csv("predators/global_wolves.csv") %>% 
  clean_names()

# Function to expand victims and extract age & sex
expand_victims <- function(victim_string, row_data) {
  row_data <- as_tibble(row_data)  
  
  victim_string <- str_replace_all(victim_string, "(male|female)(?=[A-Z])", "\\1; ")

  if (str_detect(victim_string, "[A-Za-z]+,? ?\\d{1,2}, (male|female)")) {
    people <- str_extract_all(victim_string, "[^,;]+,? ?\\d{1,2}, (male|female)")[[1]]
    
    return(map_df(people, function(person) {
      age <- str_extract(person, "\\d{1,2}") %>% as.numeric()
      sex <- str_extract(person, "male|female")
      mutate(row_data, victims = person, age = age, sex = sex)
    }))
  }

  number_match <- str_match(victim_string, "(\\d+)|([Tt]wo|[Tt]hree|[Ff]our|[Ff]ive|[Ss]ix|[Ss]even|[Ee]ight|[Nn]ine|[Tt]en|[Ee]leven|[Tt]welve|[Tt]hirteen|[Ff]ourteen|[Ff]ifteen)")
  
  if (!is.na(number_match[1])) {
    num <- suppressWarnings(as.numeric(number_match[1]))
    if (is.na(num)) {
      num <- case_when(
        str_detect(number_match[1], regex("two", ignore_case = TRUE)) ~ 2,
        str_detect(number_match[1], regex("three", ignore_case = TRUE)) ~ 3,
        str_detect(number_match[1], regex("four", ignore_case = TRUE)) ~ 4,
        str_detect(number_match[1], regex("five", ignore_case = TRUE)) ~ 5,
        str_detect(number_match[1], regex("six", ignore_case = TRUE)) ~ 6,
        str_detect(number_match[1], regex("seven", ignore_case = TRUE)) ~ 7,
        str_detect(number_match[1], regex("eight", ignore_case = TRUE)) ~ 8,
        str_detect(number_match[1], regex("nine", ignore_case = TRUE)) ~ 9,
        str_detect(number_match[1], regex("ten", ignore_case = TRUE)) ~ 10,
        str_detect(number_match[1], regex("eleven", ignore_case = TRUE)) ~ 11,
        str_detect(number_match[1], regex("twelve", ignore_case = TRUE)) ~ 12,
        str_detect(number_match[1], regex("thirteen", ignore_case = TRUE)) ~ 13,
        str_detect(number_match[1], regex("fourteen", ignore_case = TRUE)) ~ 14,
        str_detect(number_match[1], regex("fifteen", ignore_case = TRUE)) ~ 15,
        TRUE ~ 1
      )
    }
    
    return(map_df(1:num, ~ mutate(row_data, victims = "Unknown", age = NA, sex = NA)))
  }

  sex <- str_extract(victim_string, "male|female")
  age <- str_extract(victim_string, "\\d{1,2}") %>% as.numeric()
  
  return(mutate(row_data, victims = victim_string, age = age, sex = sex))
}

# Expand victims into individual rows
cleaned_df <- df %>%
  rowwise() %>%
  do(expand_victims(.$victims, .)) %>%
  ungroup()

# Clean country info from 'location' column
cleaned_df <- cleaned_df %>%
  mutate(
    country = str_extract(location, "[^,]+$") %>% str_trim(),
    country = str_remove(country, "\\.")
  ) %>%
  filter(!is.na(country) & country != "")

# Get top 15 countries by number of attacks
top_countries <- cleaned_df %>%
  count(country, sort = TRUE) %>%
  slice_head(n = 15) %>%
  pull(country)

# Filter to just those countries
filtered_df <- cleaned_df %>%
  filter(country %in% top_countries)

filtered_df <- filtered_df %>%
  filter(!is.na(type_of_attack) & type_of_attack != "")

# Plot
filtered_df %>%
  ggplot(aes(x = fct_infreq(country), fill = type_of_attack)) +
  geom_bar(position = "dodge") +
  coord_flip() +
  theme_minimal() +
  labs(
    title = "Top 15 Countries with Wolf Attacks",
    x = "Country",
    y = "Number of Attacks",
    fill = "Attack Type"
  ) +
  theme(
    plot.title = element_text(hjust = 0.5, size = 18),
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    axis.title.x = element_text(size = 14),
    axis.title.y = element_text(size = 14),
    legend.title = element_text(size = 12),
    legend.text = element_text(size = 10)
  )

After cleaning the data, you can see, Russia and France both have many attacks.

Who is King?

# 1. Summarize the number of attacks from each cleaned dataset

# Alligator
gator_attacks <- gator %>%
  filter(!is.na(date)) %>%
  nrow()

# Shark - Using shark_1 since it has most rows and was pre-cleaned
shark_attacks <- shark_1 %>%
  filter(!is.na(type), type != "Unknown") %>%
  nrow()

# Wolves - Using cleaned_df from wolf data
wolf_attacks <- cleaned_df %>%
  filter(!is.na(type_of_attack), type_of_attack != "") %>%
  nrow()

# 2. Create a comparison data frame
attack_king_df <- tibble(
  predator = c("Shark", "Alligator", "Wolf"),
  total_attacks = c(shark_attacks, gator_attacks, wolf_attacks)
)

# 3. Plot it
attack_king_df %>%
  ggplot(aes(x = reorder(predator, total_attacks), y = total_attacks, fill = predator)) +
  geom_col(width = 0.6) +
  geom_text(aes(label = total_attacks), vjust = -0.5, size = 4) +
  labs(
    title = "The King of Attacks",
    x = "Predator",
    y = "Documented Attacks"
  ) +
  scale_fill_manual(values = c("Shark" = "#FF3C38", "Alligator" = "#0C9463", "Wolf" = "#4C4C6D")) +
  theme_minimal(base_size = 16) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 20),
    legend.position = "none"
  )

Long Live King Jaws

The King of attacks is the shark. The data shows that sharks have the most attacks. Look at the map of Australia again, every marker is where a shark attack has occurred. Also, another reason why the shark data is king is due to a lack and missing data from both the wolves and gators. If there was data for Nile Crocs, there might be some competition.

knitr::include_graphics("media/shark.png")

Picture from britannica

Tour Guide Tips

When visiting Florida or Australia, watch your feet and surroundings. In Florida, pretty much everything wants to eat you from bugs to Alligators/Crocs, snakes, sharks, etc. It is a dangerous and wonderful place, as long as, you are careful. Besides, all the things that are wanting to eat you…make for a tasty meal on your dinner plate in the end. I want to return to Florida to get some croc/gator meat. Shark is not bad, it is just a fishy, chewy meat.

Australia has a larger variety of dangers, a lot of shark attacks, poisonous snakes, jellyfish, crocs, and other dangers. PBS has been my guide to Australia.

Main Points:

1- Do not underestimate a predator by thinking they are slow

2- Watch your surroundings

3- Be careful when going near any water source

4- Don’t provoke the wildlife

5- Do not feed the wildlife

6- Do not get close to the wildlife (Potential Death Risk)

7- If you are stung by a jellyfish rinse the area with water, do not urinate on it

8- If you are bit, (depending on what bit you and where you are bit) if you have a weapon, fight back.

With crocs and gators: eyes, nose, or throat are recommended to stab at. If it is a snake or a insect get help, as soon as possible.

If you are bit by a gator/croc, shark, snakes, ants, spiders, or any sort of wildlife get help ASAP, you can potentially die from a bacterial infection or rabies.

Some snakes in Florida (cottonmouth snake) are just nasty and have a bad bacteria in their mouth that will cause gangrene.

Honorable Mentions

1- Golden Labs

2- Birds

3- Jellyfish

4- Etc.

LS0tCnRpdGxlOiAiRmluYWwgUHJvamVjdDogV2hvIGlzIEtpbmcgb2YgQXR0YWNrcz8iCmF1dGhvcjogIk1lYWdoYW4gQmFycmV0dCIKZGF0ZTogIjIwMjUtMDQtMDgiCm91dHB1dDogCiAgICBodG1sX2RvY3VtZW50OgogICAgICAgIHRoZW1lOiBwYXBlcgogICAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgICB0b2M6IHRydWUKICAgICAgICB0b2NfZmxvYXQ6CiAgICAgICAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAgICAgZGZfcHJpbnQ6IGthYmxlCiAgICAgICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICAgICAgbW9kZTogc2VsZmNvbnRhaW5lZAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgY2FjaGUgPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkKYGBgCgpbUmV0dXJuIHRvIEhvbWVwYWdlXSguLi9pbmRleC5odG1sKQoKIyAqKkludHJvZHVjdGlvbioqCkluIHRoZSBmb2xsb3dpbmcgcmVwb3J0LCBJIHdpbGwgaW52ZXN0aWdhdGUgYW5kIGV4YW1pbmUgd2hpY2ggYW5pbWFsIGlzIHRoZSBraW5nIG9mIGF0dGFja3Mgd2hldGhlciBvbiBsYW5kIG9yIGluIHRoZSB3YXRlciwgYnkgY29tcGFyaW5nIHRoZSBhdHRhY2tzIGZyb20gc2hhcmtzLCB3b2x2ZXMsIGFuZCBhbGxpZ2F0b3JzLiBXaGlsZSB0aGlzIGRhdGEgaGFzIGFscmVhZHkgYmVlbiBzb21ld2hhdCBjbGVhbmVkIGFuZCBjb250YWlucyBmYWlybHkgc2ltcGxlIGluZm9ybWF0aW9uLCB0aGlzIGZpbmFsIHByb2plY3QgYWltcyB0byBpbnZlc3RpZ2F0ZSB0aGUgZGlzcGFyaXRpZXMgYmV0d2VlbiB0aGVzZSB0aHJlZSBhbmltYWxzLCB0aGUgYXR0YWNrIGxvY2F0aW9ucywgYW5kIHRoZSBlZmZlY3RlZCBwb3B1bGF0aW9uLiBJbiBzaW1wbGVyIHRlcm1zLCB3aG8gaXMgcmVzcG9uc2libGUgZm9yIHRoZSBtb3N0IGF0dGFja3M/IFdoaWNoIHBvcHVsYXRpb25zIGFyZSB0aGUgbW9zdCBlZmZlY3RlZD8gV2VyZSB0aGVzZSBhdHRhY2tzIHByb3Zva2VkIG9yIG5vdD8gVGhlc2UgYXJlIGp1c3Qgc29tZSBvZiB0aGUgcXVlc3Rpb25zIEkgaG9wZSB0byBleHBsb3JlIGluIHRoaXMgd3JpdGluZy4gCgojICoqQmFja2dyb3VuZCoqClRoaXMgcHJvamVjdCB3YXMgaW5zcGlyZWQgaW4gcGFydCBieSBteSBmYW1pbHksIG15IG1vdGhlciBpcyBmcm9tIEZsb3JpZGEgYW5kIHRoZXJlIGhhdmUgYmVlbiBzb21lIHZlcnkgaW50ZXJlc3RpbmcgZG9jdW1lbnRhcmllcyBkb25lIG9uIGFsbCB0aGVzZSBhbmltYWxzLiBJdCB3YXMgYWxzbyBpbnNwaXJlZCBieSBnZW5lcmFsIGhhcHBlbiBzdGFuY2U6IEkgZm91bmQgYSB2ZXJ5IG5pY2UgZGF0YSBzZXQgb24gS2FnZ2xlIGFuZCBmZWx0IGl0IGNvdWxkIGJlIGFuIGludGVyZXN0aW5nIHRha2Ugb24gYSBzZWVtaW5nbHkgZHVsbCBkYXRhIHNldC4gQXMgbWVudGlvbmVkLCB0aGlzIGRhdGEgc2V0IHdhcyBmb3VuZDogCgpbRmF0YWwgQWxsaWdhdG9yIEF0dGFja3NdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvZGFuZWxhL2ZhdGFsLWFsbGlnYXRvci1hdHRhY2tzLXVzP3Jlc291cmNlPWRvd25sb2FkJnNlbGVjdD1mYXRhbF9hbGxpZ2F0b3JfYXR0YWNrc19VUy5jc3YpCgpbU2hhcmsgQXR0YWNrc10oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9mZWxpcGVlc2Mvc2hhcmstYXR0YWNrLWRhdGFzZXQ/cGhhc2U9RmluaXNoU1NPUmVnaXN0cmF0aW9uJnJldHVyblVybD0lMkZkYXRhc2V0cyUyRmZlbGlwZWVzYyUyRnNoYXJrLWF0dGFjay1kYXRhc2V0JTJGdmVyc2lvbnMlMkYxJTNGcmVzb3VyY2UlM0Rkb3dubG9hZCZTU09SZWdpc3RyYXRpb25Ub2tlbj1DZkRKOFBIU0NMOWs5czFIdUoyY1JGQkZodWhncHhOMGdfQVRESVR6Xy1jWFZHLW41LVM4UGNBblpkZ0RYSGJuN3VkMGlhVllMZVlXa1luRlRZNk5jNEpGdDFueVdBWnNUdWhSOHZTUHYzb2s1VFA0QXRSUks5LUl6R0RxU3paS1VHeE1heUtLNU5La2RXZ2V3VVZZUE1GMWFKbDRwaFBCNE9id1hsMkFLNzY5OENFMjMweXNzOWtnYkFWS2NaQUNCZzAwRm1TUFBrVHNZR2hsV3U0ejNWcmV6dlpEWG9MbjJlWWF5STA3ODRKREFuYWExTDVLVnN2cHpvbEdUazlUOGhuN3VEdFgyOXJ3TlJhUVd5MTlCc1YwS1o3VGNmRGZGcFl2UkQ4clNNcnE0eUV1bDctQ1JhMkwxUjVxV3Z4RU9ZTWxHSS1WRk44N3NnYWJPUHJnX0NKNmpjSmFWbzBDY3NRJkRpc3BsYXlOYW1lPU1lYWdoYW4rQmFycmV0dCkKCltTaGFyayBBdHRhY2tzIEJ5IEhlbWlzcGhlcmVzXShodHRwczovL3d3dy5rYWdnbGUuY29tL2NvZGUvaWNlY3JlYW00L3NoYXJrLWF0dGFja3MtYnktaGVtaXNwaGVyZXMvbm90ZWJvb2spIAoKW0dsb2JhbCBXb2xmIEF0dGFja3NdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvZGFuZWxhL2dsb2JhbC13b2xmLWF0dGFja3M/c2VsZWN0PWdsb2JhbF93b2x2ZXMuY3N2KSAKClRoZSBkYXRhIHNldCBjb25zaXN0cyBvZiB2YXJpb3VzIHJlcG9ydGVkIHN0YXRpc3RpY3MgcmVnYXJkaW5nIHRoZXNlIGRpZmZlcmVudCBhdHRhY2tzLiBNb3N0IHR5cGVzIG9mIGF0dGFja3Mgd2VyZSBub3Qgb25seSBwcmVkYXRvcnksIGJ1dCB1bnByb3Zva2VkLiBIb3dldmVyLCBzb21lIGluZGl2aWR1YWxzIHdlcmUgcmVwb3J0ZWQgdG8gcHJvdm9rZSB0aGUgYW5pbWFsLiBEaWZmZXJlbnQgYWdlIGdyb3VwcyB3ZXJlIGF0dGFja2VkIGVhY2ggdGltZS4gCgpQcmV2ZW50aW9uIHdvdWxkIGJlIGdyZWF0LCBidXQgdGhlcmUgYXJlIG5vdCBzaWducyBmb3IgdGhvc2UgdGhhdCB3aWxsIGFuZCBjb3VsZCBiZSBhdHRhY2tlZC4gQWxsaWdhdG9ycywgc2hhcmtzLCBhbmQgd29sdmVzIGhhdmUgZGlmZmVyZW50IHJlYXNvbnMgdG8gYXR0YWNrLiAgCgojICoqRGF0YSoqCmBgYHtyLCBlY2hvID0gVFJVRX0KIyBsb2FkIGFsbCBuZWNlc3NhcnkgbGlicmFyaWVzIApsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShyZWFkcikKCiMgcmVhZGluZyBpbiBrYWdnbGUgZGF0YSBzZXRzIApnYXRvciA8LSByZWFkLmNzdigicHJlZGF0b3JzL2ZhdGFsX2FsbGlnYXRvcl9hdHRhY2tzX1VTLmNzdiIpCgpnX3dvbHZlcyA8LSByZWFkLmNzdigicHJlZGF0b3JzL2dsb2JhbF93b2x2ZXMuY3N2IikKCnNoYXJrXzEgPC0gcmVhZC5jc3YoInByZWRhdG9ycy9TaGFya19hdHRhY2tzL2F0dGFja3MuY3N2IikKCnNoYXJrXzIgPC0gcmVhZC5jc3YoInByZWRhdG9ycy9zaGFya19hdHRhY2tzLmNzdiIpCgpzaGFya18zIDwtIHJlYWQuY3N2KCJwcmVkYXRvcnMvU2hhcmtfYXR0YWNrcy9saXN0X2Nvb3JfYXVzdHJhbGlhLmNzdiIpCgpgYGAKVGhpcyBkYXRhIHNldCB3YXMgcmV0cmlldmVkIGZyb20gS2FnZ2xlIGFuZCBoYXMgYWxyZWFkeSBiZWVuICoqc29tZXdoYXQqKiBjbGVhbmVkIGZvciBhbmFseXNpcy4gSG93ZXZlciwgdGhlcmUgYXJlIHNvbWUgY2hhbmdlcyBJIHdhbnRlZCB0byBtYWtlIHRvIHRoZSBkYXRhIHN0cnVjdHVyZSwgY2hhbmdpbmcgbWlzc2luZyB2YWx1ZXMvZW1wdHkgc3BhY2VzLCBjbGVhbmluZyB0aGUgbmFtZXMsIGFuZCBpbXByb3ZpbmcgY2hhcmFjdGVycyBmb3VuZCB0aHJvdWdob3V0IHRoZSBkYXRhIHNldC4gVGhlIGZvbGxvd2luZyBjb2RlIGFuZCBvdXRwdXRzIGRlbW9uc3RyYXRlIHRoZSBjaGFuZ2VzIEkndmUgbWFkZSB0byBhbGxvdyBmb3Igc21vb3RoZXIgZGF0YSBhbmFseXNpczogCgpgYGB7ciwgZWNobz1UUlVFfQoKIyBjb252ZXJ0IGNvbHVtbiB0aXRsZXMgdG8gc25ha2VfY2FzZSAKCmdhdG9yIDwtY2xlYW5fbmFtZXMoZ2F0b3IpCgpnX3dvbHZlcyA8LWNsZWFuX25hbWVzKGdfd29sdmVzKQoKc2hhcmtfMSA8LSBjbGVhbl9uYW1lcyhzaGFya18xKQoKc2hhcmtfMiA8LWNsZWFuX25hbWVzKHNoYXJrXzIpCmBgYAoKYGBge3IgZXZhbCA9IFRSVUV9CiMgY29udmVydHMgYWxsIE4vQSBjaHIgdmFsdWVzIHRvIGFjdHVhbCBtaXNzaW5nIHZhbHVlcyBhbmQgZmlsbHMgaW4gZW1wdHkgc3BhY2VzIHdpdGggbWlzc2luZyB2YWx1ZXMgCgpnX3dvbHZlcyR0eXBlX29mX2F0dGFja1tpcy5uYShnX3dvbHZlcyR0eXBlX29mX2F0dGFjaykgfCBnX3dvbHZlcyR0eXBlX29mX2F0dGFjayA9PSAiIl0gPC0gIlVua25vd24iCgpzaGFya18yJHR5cGVbaXMubmEoc2hhcmtfMiR0eXBlKSB8IHNoYXJrXzIkdHlwZSA9PSAiSW52YWxpZCJdIDwtICJVbmtub3duIgoKc2hhcmtfMSA8LSBzaGFya18xWyFpcy5uYShzaGFya18xJHR5cGUpLCBdIApzaGFya18xX3N1YnNldCA8LSBzaGFya18xWzE6NjMwMiwgXQpucm93KHNoYXJrXzEpCmxlbmd0aChzaGFya18xJHR5cGUpCgojIENoZWNrIHdoaWNoIHJvd3MgaGF2ZSBOQSBvciBpbnZhbGlkIHZhbHVlcwp0YWJsZShpcy5uYShzaGFya18xJHR5cGUpKSAgCnRhYmxlKHNoYXJrXzEkdHlwZSA9PSAiSW52YWxpZCIpICAKCiMgUmVwbGFjZSBvbmx5IE5BcyBmaXJzdCwgdGhlbiBJbnZhbGlkcwpzaGFya18xJHR5cGVbaXMubmEoc2hhcmtfMSR0eXBlKV0gPC0gIlVua25vd24iCnNoYXJrXzEkdHlwZVtzaGFya18xJHR5cGUgPT0gIkludmFsaWQiXSA8LSAiVW5rbm93biIKCgojIGNvbnZlcnRzIGRhdGEgc3RydWN0dXJlIHRvIG1vcmUgYXBwcm9wcmlhdGUgZGF0YSB0eXBlcwpnYXRvciA8LWdhdG9yICU+JSAKICBtdXRhdGUobG9jYXRpb24gPSBzdHJfZXh0cmFjdChkZXRhaWxzLCAiKE1pYW1pfEZsb3JpZGF8R2VvcmdpYXxUZXhhc3xMb3Vpc2lhbmF8U291dGggQ2Fyb2xpbmEpIiksCiAgICAgICAgIGxvY2F0aW9uID0gaWZlbHNlKGxvY2F0aW9uID09ICJNaWFtaSIsICJGbG9yaWRhIiwgbG9jYXRpb24pKQoKYGBgCgojICoqQWxsaWdhdG9yKioKCgpgYGB7ciwgb3V0LndpZHRoPSI3MCUiLCBvdXQuaGVpZ2h0PSI3MCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygibWVkaWEvZ2F0b3IucG5nIikKYGBgCgpQaWN0dXJlIGNhbWUgZnJvbSBbVHJlZUh1Z2dlcl0oaHR0cHM6Ly93d3cudHJlZWh1Z2dlci5jb20vYWxsaWdhdG9yLWZhY3RzLTUxMTkyMTQpCgpBbGxpZ2F0b3JzIGFyZSBiZWF1dGlmdWwgYW5kIGRhbmdlcm91cyBhbmltYWxzLiBUaGlzIGRhdGEgb25seSBzaG93cyBhIHNtYWxsIGFtb3VudCBvZiBkZWF0aHMgdGhhdCBoYXZlIGJlZW4gY2F1c2VkIGJ5IGFsbGlnYXRvcnMuIFRoZXJlIHdhcyBubyBpbmZvcm1hdGlvbiBhYm91dCBjcm9jb2RpbGVzIChjcm9jcyksIGV2ZW4gdGhvdWdoIHRoZXkgZG8gaGF2ZSBhIGhhbmQgaW4gbWFueSBkZWF0aHMgb3ZlciB0aGUgeWVhcnMsIHNpbmNlIGludmFkaW5nIHRoZSBTb3V0aC4gVGhpcyBkYXRhIHNob3dzIHRoYXQgRmxvcmlkYSBoYXMgaGFkIHRoZSBtb3N0IG51bWJlciBvZiBhdHRhY2tzLiBJIGhhdmUgbGVhcm5lZCBvdmVyIHRoZSB5ZWFycywgdG8ga2VlcCBhbiBleWUgb3V0IHdoZW5ldmVyIGJ5IHdhdGVyIG9uIHRoZSBTb3V0aGVybiBjb2FzdC4gWW91IG5ldmVyIGtub3cgd2hhdCBtaWdodCBzbmFwIHlvdSB1cC4gCgpgYGB7ciwgZWNobyA9IEZBTFNFfQpnYXRvciAlPiUKICBtdXRhdGUoZGF0ZSA9IGFzLkRhdGUoZGF0ZSwgZm9ybWF0ID0gIiVCICVkLCAlWSIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShkYXRlKSkgJT4lIAogIGZpbHRlcihhZ2UgIT0gIj8iKSAlPiUKICBtdXRhdGUoYWdlID0gYXMubnVtZXJpYyhhZ2UpKSAlPiUKICBmaWx0ZXIoYWdlID49IDIgJiBhZ2UgPD0gODEpICU+JQogIG11dGF0ZSh5ZWFyID0gYXMuaW50ZWdlcihmb3JtYXQoZGF0ZSwgIiVZIikpKSAlPiUgIAogIGFycmFuZ2UoYWdlKSAlPiUKICBncm91cF9ieShsb2NhdGlvbikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZmFjdG9yKHllYXIpLCB5ID0gYWdlLCBjb2xvciA9IGxvY2F0aW9uKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCBzaXplID0gMTQpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICJib2xkIikKICApICsKICBsYWJzKHggPSAiWWVhciIsIHkgPSAiQWdlIiwgdGl0bGUgPSAiR2F0b3IgQXR0YWNrczogQWdlcyB2cy4gTG9jYXRpb24iKQoKYGBgCgoKYGBge3IsIGVjaG89RkFMU0V9CmRlYXRocyA8LWdhdG9yICU+JQogIGZpbHRlcihsb2NhdGlvbiAhPSAiPyIpICU+JSAgCiAgZmlsdGVyKHNleCAhPSAiPyIpICU+JSAgICAgICAKICBncm91cF9ieShsb2NhdGlvbiwgc2V4KSAlPiUKICB0YWxseSgpCgpwcmludChkZWF0aHMpCgp2aWN0aW1zX2J5X3N0YXRlIDwtIGRlYXRocyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbG9jYXRpb24sIHkgPSBuLCBmaWxsID0gc2V4KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsgIAogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgc2l6ZSA9IDE0KSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpCiAgKSArIAogIGxhYnMoCiAgICB0aXRsZSA9ICJBbGxpZ2F0b3IgQXR0YWNrcyBieSBTdGF0ZSIsCiAgICB4ID0gIlN0YXRlIiwgeSA9ICJOdW1iZXIgb2YgVmljdGltcyIsIGZpbGwgPSAiU2V4IgogICkKCgoKdmljdGltc19ieV9zdGF0ZQpgYGAKCiMgKipVbmV4cGVjdGVkIFNoYXJrIEF0dGFja3MqKgpXaGVuIEkgZmlyc3Qgc3RhcnRlZCB0cnlpbmcgdG8gY3JlYXRlIHRoaXMgcGxvdCwgdGhpcyB3YXMgdGhlIHJlc3VsdC4gQXR0YWNrcyBoYXBwZW5pbmcgYWJvdmUgR3JlZW5sYW5kLiBJIGxlYXJuZWQgaG93IHdyb25nIEkgd2FzLiAKYGBge3IsIG91dC53aWR0aD0iNzAlIiwgb3V0LmhlaWdodD0iNzAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIm1lZGlhL1VuZXhwZWN0ZWRfQXR0YWNrcy5wbmciKQpgYGAKCiMgKipTaGFya3MqKgoKCmBgYHtyLCBvdXQud2lkdGg9IjcwJSIsIG91dC5oZWlnaHQ9IjcwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJtZWRpYS9zaGFyay5wbmciKQpgYGAKClBpY3R1cmUgZnJvbSBbYnJpdGFubmljYV0oaHR0cHM6Ly93d3cuYnJpdGFubmljYS5jb20vYW5pbWFsL3NoYXJrKQoKCgpJZiBhbnkgb2YgeW91IGhhdmUgYW4gdW5yZWFsaXN0aWMgZmVhciB0aGF0IHRoZXJlIGlzIHNvbWV0aGluZyBpbiB0aGUgd2F0ZXIgYW5kIHlvdSB3aWxsIGdldCBhdHRhY2tlZCwgeW91J3JlIG5vdCBhbG9uZS4gTG9vayB3aGF0IGlzIGhhcHBlbmluZyBpbiBBdXN0cmFsaWEuIFpvb20gb3V0IGFuZCBzZWUgd2hhdCBpcyBoYXBwZW5pbmcuCgpgYGB7ciwgZWNobyA9IFRSVUV9Cgpjb2xuYW1lcyhzaGFya18zKSA8LSBjKCJsYXRpdHVkZSIsICJsb25naXR1ZGUiKQpjZW50ZXJfbGF0IDwtIC0yNS4yNzQ0CmNlbnRlcl9sb24gPC0gMTMzLjc3NTEKem9vbV9sZXZlbCA8LSA1ICAKCm1hcCA8LSBsZWFmbGV0KCkgJT4lCiAgYWRkVGlsZXMoKSAlPiUgIAogIHNldFZpZXcoY2VudGVyX2xvbiwgY2VudGVyX2xhdCwgem9vbSA9IHpvb21fbGV2ZWwpCgpmb3IgKGkgaW4gMTpucm93KHNoYXJrXzMpKSB7CiAgbWFwIDwtIG1hcCAlPiUgYWRkTWFya2VycyhsbmcgPSBzaGFya18zJGxvbmdpdHVkZVtpXSwgbGF0ID0gc2hhcmtfMyRsYXRpdHVkZVtpXSkKfQoKbWFwCgpgYGAKCgpgYGB7ciwgb3V0LndpZHRoPSIxMDAlIiwgb3V0LmhlaWdodD0iMTAwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJtZWRpYS9BdXN0cmFsaWEucG5nIikKYGBgCgoKVGhpcyBpcyB3aGF0IHRoZSBtYXAgbG9va3MgbGlrZSB3aGVuIHpvb21lZCBvdXQuIENyYXp5LCByaWdodD8KCgojICAqKk1vcmUgQXR0YWNrcyoqCmBgYHtyLCBlY2hvPVRSVUV9CgpzaGFya18xJHR5cGVbaXMubmEoc2hhcmtfMSR0eXBlKSB8IHNoYXJrXzEkdHlwZSA9PSAiIl0gPC0gIlVua25vd24iCnNoYXJrXzEkdHlwZVtpcy5uYShzaGFya18xJHR5cGUpIHwgc2hhcmtfMSR0eXBlID09ICJJbnZhbGlkIl0gPC0gIlVua25vd24iCnNoYXJrXzFfc3Vic2V0IDwtIHNoYXJrXzFbMTo2MzAyLCBdCgpzaGFya3MgPC0gc2hhcmtfMSAlPiUgCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHR5cGUpKSArCiAgZ2VvbV9iYXIoYWVzKHkgPSAuLmNvdW50Li4pKSArIAogIGdlb21fdGV4dChzdGF0ID0gJ2NvdW50JywgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgdmp1c3QgPSAtMC41KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTQpLCAgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgIAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiksICAKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwgIAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKSArIAogIGxhYnModGl0bGUgPSAiU2hhcmsgQXR0YWNrcyBieSBUeXBlIiwgCiAgICAgICB4ID0gIlR5cGUgb2YgQXR0YWNrIiwgCiAgICAgICB5ID0gIkNvdW50IG9mIEF0dGFja3MiKQoKIyBQbG90IHRoZSBjaGFydApwbG90KHNoYXJrcykKCmBgYAoKCkRvZXMgYW55b25lIGhhdmUgYW4gaWRlYSB3aGF0IGJvYXRvbWcgaXM/IEkgdGhpbmsgdGhleSBtZWFudCBib2F0aW5nLCBidXQgbWVzc2VkIHVwIG9uIHRoZWlyIEVuZ2xpc2guIEl0IGlzIHVuZGVyc3RhbmRhYmxlIHRvIGEgZGVncmVlLCBFbmdsaXNoIGlzIGhhcmQuIAoKCiMgKipNb3JlIFNoYXJrIEF0dGFja3MqKgpgYGB7ciwgZWNobyA9IFRSVUV9CgpzaGFya18yJHR5cGVbaXMubmEoc2hhcmtfMiR0eXBlKSB8IHNoYXJrXzIkdHlwZSA9PSAiSW52YWxpZCJdIDwtICJVbmtub3duIgoKc2hhcmtfMiAlPiUgCiAgZ3JvdXBfYnkoYXJlYSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHR5cGUpKSArCiAgZ2VvbV9iYXIoYWVzKHkgPSAuLmNvdW50Li4pKSArIAogIGdlb21fdGV4dChzdGF0ID0gJ2NvdW50JywgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgdmp1c3QgPSAtMC41KSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxNCksICAKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksICAKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLCAgCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSAgIAogICkgKyAKICBsYWJzKHRpdGxlID0gIlNoYXJrIEF0dGFja3MgYnkgVHlwZSIsIAogICAgICAgeCA9ICJUeXBlIG9mIEF0dGFjayIsIAogICAgICAgeSA9ICJDb3VudCBvZiBBdHRhY2tzIikKCmBgYApgYGB7ciwgZWNobz1UUlVFfQoKdG9wX2NvdW50cmllcyA8LSBzaGFya18yICU+JQogIGNvdW50KGNvdW50cnksIHNvcnQgPSBUUlVFKSAlPiUKICB0b3BfbigxNSwgbikgJT4lCiAgcHVsbChjb3VudHJ5KQoKCnNoYXJrXzIgJT4lCiAgZmlsdGVyKGNvdW50cnkgIT0gIiIsY291bnRyeSAlaW4lIHRvcF9jb3VudHJpZXMpICU+JQogIG11dGF0ZShtb250aCA9IG1vbnRoKGFzLkRhdGUoZGF0ZSwgZm9ybWF0ID0gIiVkLSVCLSVZIiksIGxhYmVsID0gVFJVRSkpICU+JQogIGZpbHRlcighaXMubmEobW9udGgpKSAlPiUKICBncm91cF9ieShjb3VudHJ5LCBtb250aCkgJT4lCiAgc3VtbWFyaXNlKGF0dGFja3MgPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIG11dGF0ZShhcmVhID0gZmN0X3Jlb3JkZXIoY291bnRyeSwgYXR0YWNrcywgLmZ1biA9IHN1bSkpICU+JQogIGdncGxvdChhZXMoeCA9IGNvdW50cnksIHkgPSBtb250aCkpICsKICBnZW9tX3BvaW50KGFlcyhzaXplID0gYXR0YWNrcywgY29sb3IgPSBhdHRhY2tzKSwgYWxwaGEgPSAwLjcpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDIsIDEwKSkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJza3libHVlIiwgaGlnaCA9ICJyZWQiKSArCiAgbGFicygKICAgIHggPSAiQ291bnRyeSIsCiAgICB5ID0gIk1vbnRoIiwKICAgIHNpemUgPSAiTnVtYmVyIG9mIEF0dGFja3MiLAogICAgY29sb3IgPSAiTnVtYmVyIG9mIEF0dGFja3MiLAogICAgdGl0bGUgPSAiU2hhcmsgQXR0YWNrcyBieSBNb250aCIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogIGNvb3JkX2ZsaXAoKQoKYGBgCgoKIyAqKlVTQSoqCgpgYGB7ciwgZWNobz1UUlVFfQoKIyBMaXN0IG9mIGFsbCBVLlMuIHN0YXRlcwp1c19zdGF0ZXMgPC0gYygKICAiQWxhYmFtYSIsICJBbGFza2EiLCAiQXJpem9uYSIsICJBcmthbnNhcyIsICJDYWxpZm9ybmlhIiwgIkNvbG9yYWRvIiwgIkNvbm5lY3RpY3V0IiwgCiAgIkRlbGF3YXJlIiwgIkZsb3JpZGEiLCAiR2VvcmdpYSIsICJIYXdhaWkiLCAiSWRhaG8iLCAiSWxsaW5vaXMiLCAiSW5kaWFuYSIsICJJb3dhIiwgCiAgIkthbnNhcyIsICJLZW50dWNreSIsICJMb3Vpc2lhbmEiLCAiTWFpbmUiLCAiTWFyeWxhbmQiLCAiTWFzc2FjaHVzZXR0cyIsICJNaWNoaWdhbiIsIAogICJNaW5uZXNvdGEiLCAiTWlzc2lzc2lwcGkiLCAiTWlzc291cmkiLCAiTW9udGFuYSIsICJOZWJyYXNrYSIsICJOZXZhZGEiLCAKICAiTmV3IEhhbXBzaGlyZSIsICJOZXcgSmVyc2V5IiwgIk5ldyBNZXhpY28iLCAiTmV3IFlvcmsiLCAiTm9ydGggQ2Fyb2xpbmEiLCAKICAiTm9ydGggRGFrb3RhIiwgIk9oaW8iLCAiT2tsYWhvbWEiLCAiT3JlZ29uIiwgIlBlbm5zeWx2YW5pYSIsICJSaG9kZSBJc2xhbmQiLCAKICAiU291dGggQ2Fyb2xpbmEiLCAiU291dGggRGFrb3RhIiwgIlRlbm5lc3NlZSIsICJUZXhhcyIsICJVdGFoIiwgIlZlcm1vbnQiLCAKICAiVmlyZ2luaWEiLCAiV2FzaGluZ3RvbiIsICJXZXN0IFZpcmdpbmlhIiwgIldpc2NvbnNpbiIsICJXeW9taW5nIgopCgojIE5vdyBmaWx0ZXIgYmFzZWQgb24gVS5TLiBzdGF0ZXMKc2hhcmtfMiAlPiUKICBmaWx0ZXIoY291bnRyeSA9PSAiVVNBIiwgYXJlYSAlaW4lIHVzX3N0YXRlcykgJT4lCiAgbXV0YXRlKG1vbnRoID0gbW9udGgoYXMuRGF0ZShkYXRlLCBmb3JtYXQgPSAiJWQtJUItJVkiKSwgbGFiZWwgPSBUUlVFKSkgJT4lCiAgZmlsdGVyKCFpcy5uYShtb250aCkpICU+JQogIGdyb3VwX2J5KGFyZWEsIG1vbnRoKSAlPiUKICBzdW1tYXJpc2UoYXR0YWNrcyA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgbXV0YXRlKGFyZWEgPSBmY3RfcmVvcmRlcihhcmVhLCBhdHRhY2tzLCAuZnVuID0gc3VtLCAuZGVzYyA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhcmVhLCB5ID0gbW9udGgpKSArCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGF0dGFja3MsIGNvbG9yID0gYXR0YWNrcyksIGFscGhhID0gMC43KSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygyLCAxMCkpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAic2t5Ymx1ZSIsIGhpZ2ggPSAicmVkIikgKwogIGxhYnMoCiAgICB4ID0gIlN0YXRlcyIsCiAgICB5ID0gIk1vbnRoIiwKICAgIHNpemUgPSAiTnVtYmVyIG9mIEF0dGFja3MiLAogICAgY29sb3IgPSAiTnVtYmVyIG9mIEF0dGFja3MiLAogICAgdGl0bGUgPSAiU2hhcmsgQXR0YWNrcyBieSBNb250aCBpbiBVLlMuQS4iCiAgKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsKICBjb29yZF9mbGlwKCkKCmBgYAoKCiMgKipXaGVuIENvbXBhcmluZzogVVNBIHZzLiBBdXN0cmFsaWEqKgoKYGBge3IsIGVjaG89VFJVRX0Kc2hhcmtfMiAlPiUKICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIlVTQSIsICJBVVNUUkFMSUEiKSkgJT4lCiAgbXV0YXRlKG1vbnRoID0gbW9udGgoYXMuRGF0ZShkYXRlLCBmb3JtYXQgPSAiJWQtJUItJVkiKSwgbGFiZWwgPSBUUlVFKSkgJT4lCiAgZmlsdGVyKCFpcy5uYShtb250aCkpICU+JQogIGdyb3VwX2J5KGNvdW50cnksIG1vbnRoKSAlPiUKICBzdW1tYXJpc2UoYXR0YWNrcyA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbW9udGgsIHkgPSBhdHRhY2tzKSkgKwogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBhdHRhY2tzLCBjb2xvciA9IGF0dGFja3MpLCBhbHBoYSA9IDAuNykgKwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMiwgMTApKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gInNreWJsdWUiLCBoaWdoID0gInJlZCIpICsKICBsYWJzKAogICAgeCA9ICJNb250aCIsCiAgICB5ID0gIk51bWJlciBvZiBBdHRhY2tzIiwKICAgIHNpemUgPSAiTnVtYmVyIG9mIEF0dGFja3MiLAogICAgY29sb3IgPSAiTnVtYmVyIG9mIEF0dGFja3MiLAogICAgdGl0bGUgPSAiTW9udGhseSBTaGFyayBBdHRhY2tzOiBVU0EgdnMgQXVzdHJhbGlhIgogICkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgZmFjZXRfd3JhcCh+IGNvdW50cnksIG5jb2wgPSAxKQoKYGBgCgojICAqKldvbHZlczogQmVmb3JlIENsZWFuaW5nKioKCgpgYGB7ciwgb3V0LndpZHRoPSI3MCUiLCBvdXQuaGVpZ2h0PSI3MCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygibWVkaWEvd29sdmVzLnBuZyIpCmBgYAoKClBpY3R1cmUgZnJvbSBbYnJpdGFubmljYS1Xb2x2ZXNdKGh0dHBzOi8vd3d3LmJyaXRhbm5pY2EuY29tL2FuaW1hbC93b2xmKQoKCmBgYHtyLCBlY2hvPVRSVUV9Cmdfd29sdmVzJHR5cGVfb2ZfYXR0YWNrW2lzLm5hKGdfd29sdmVzJHR5cGVfb2ZfYXR0YWNrKSB8IGdfd29sdmVzJHR5cGVfb2ZfYXR0YWNrID09ICIiXSA8LSAiVW5rbm93biIKCndvbHZlcyA8LSBnX3dvbHZlcyAlPiUgCiAgZ3JvdXBfYnkodHlwZV9vZl9hdHRhY2spICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB0eXBlX29mX2F0dGFjaykpICArCiAgZ2VvbV9iYXIoYWVzKHkgPSAuLmNvdW50Li4pKSArIAogIGdlb21fdGV4dChzdGF0ID0gJ2NvdW50JywgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgdmp1c3QgPSAtMC41KSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxNCksICAKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksICAKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpICAKICApICsKICBsYWJzKHggPSAiVHlwZXMgb2YgQXR0YWNrcyIsIHkgPSAiVmljdGltIENvdW50IikKCnBsb3Qod29sdmVzKQoKYGBgCgoKV2hlbiBJIHdhcyBsb29raW5nIGFuZCB0cnlpbmcgdG8gY2xlYW4gdGhlIGRhdGEsIHRoZXJlIHdlcmUgbWFueSBmYWN0b3JzIHRoYXQgYWZmZWN0ZWQgaXQuIFRoZSBkYXRhIHdhcyBub3QgcHJldHR5IGV2ZW4gYWZ0ZXIgdHJ5aW5nIHRvIGNsZWFuIGl0LiBUaGUgYXR0YWNrcyBhcmUgZXZlbiBoaWdoZXIgdGhhbiBkYXRhIGFib3ZlLiBUaGVyZSB3YXMgc29tZSBkYXRhIHRoYXQgcmVwcmVzZW50ZWQgMTUgcGVvcGxlIHRoYXQgd2VyZSBraWxsZWQgYnkgd29sdmVzLiBBbGwgMTUgcGVvcGxlIHdlcmUgcGxhY2VkIG9uIHRoZSBzYW1lIGxpbmUuIFRoaXMgaXMgaG93IGl0IGxvb2tlZCBiZWZvcmUgcmVhbGx5IGNsZWFuaW5nIHRoZSBkYXRhLiAKCmBgYHtyLCBlY2hvPVRSVUV9CiMgUmVhZCB0aGUgQ1NWIGZpbGUgKGFzc3VtaW5nIGl0J3Mgc2F2ZWQgYXMgJ2dsb2JhbF93b2x2ZXMuY3N2JykKZGF0YSA8LSByZWFkLmNzdigicHJlZGF0b3JzL2dsb2JhbF93b2x2ZXMuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKZGF0YSA8LSBjbGVhbl9uYW1lcyhkYXRhKQoKIyBVc2UgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZXh0cmFjdCB0aGUgY291bnRyeSBmcm9tIHRoZSAnTG9jYXRpb24nIGNvbHVtbgpkYXRhJGNvdW50cnkgPC0gc3ViKCIuKixcXHMqKC4qKSQiLCAiXFwxIiwgZGF0YSRsb2NhdGlvbikKCiMgRXh0cmFjdCB0aGUgY291bnRyeSBmcm9tIGxvY2F0aW9uIHN0cmluZwpkYXRhJGNvdW50cnkgPC0gc3RyX2V4dHJhY3QoZGF0YSRsb2NhdGlvbiwgIlteLF0rJCIpCgojIFRyaW0gYW55IGxlYWRpbmcvdHJhaWxpbmcgd2hpdGVzcGFjZQpkYXRhJGNvdW50cnkgPC0gdHJpbXdzKGRhdGEkY291bnRyeSkKCiMgUmVwbGFjZSBibGFuayBib3ggd2l0aCBOQQpkYXRhIDwtIGRhdGEgJT4lCiAgbXV0YXRlKHR5cGVfb2ZfYXR0YWNrID0gaWZlbHNlKHR5cGVfb2ZfYXR0YWNrID09ICIiLCBOQSwgdHlwZV9vZl9hdHRhY2spKQoKZGF0YSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY291bnRyeSwgZmlsbCA9IHR5cGVfb2ZfYXR0YWNrKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGNvb3JkX2ZsaXAoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsgIAogIGxhYnModGl0bGUgPSAiQXR0YWNrcyBhbmQgQ291bnRyeSIsCiAgICAgICB4ID0gIkNvdW50cnkiLAogICAgICAgeSA9ICJDb3VudCBvZiBBdHRhY2tzIikgKwogIHRoZW1lX21pbmltYWwoKSsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSAgCmBgYAoKYGBge3IsIG91dC53aWR0aD0iMTAwJSIsIG91dC5oZWlnaHQ9IjEwMCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygibWVkaWEvd29sdmVzX2F0dGFja3MucG5nIikKYGBgCgoKIyAqKkNsZWFuLWlzaCBXb2x2ZXMgRGF0YSoqCgpgYGB7ciwgZWNobz1UUlVFfQojIyMgQXR0ZW1wdCAyCiMgTG9hZCB0aGUgQ1NWCmRmIDwtIHJlYWRfY3N2KCJwcmVkYXRvcnMvZ2xvYmFsX3dvbHZlcy5jc3YiKSAlPiUgCiAgY2xlYW5fbmFtZXMoKQoKIyBGdW5jdGlvbiB0byBzcGxpdCBvciBkdXBsaWNhdGUgdmljdGltcwpleHBhbmRfdmljdGltcyA8LSBmdW5jdGlvbih2aWN0aW1fc3RyaW5nLCByb3dfZGF0YSkgewogIHJvd19kYXRhIDwtIGFzX3RpYmJsZShyb3dfZGF0YSkgIAogIAogICMgSW5zZXJ0IHNlcGFyYXRvciB3aGVyZSBnZW5kZXIgaXMgamFtbWVkIHdpdGggbmV4dCBuYW1lLCBsaWtlICJtYWxlQWxleCIKICB2aWN0aW1fc3RyaW5nIDwtIHN0cl9yZXBsYWNlX2FsbCh2aWN0aW1fc3RyaW5nLCAiKG1hbGV8ZmVtYWxlKSg/PVtBLVpdKSIsICJcXDE7ICIpCiAgCiAgIyBDYXNlIDE6IG11bHRpcGxlIG5hbWVkIHBlb3BsZQogIGlmIChzdHJfZGV0ZWN0KHZpY3RpbV9zdHJpbmcsICJbQS1aYS16XSssIFxcZHsxLDJ9LCAobWFsZXxmZW1hbGUpIikpIHsKICAgIHBlb3BsZSA8LSBzdHJfZXh0cmFjdF9hbGwodmljdGltX3N0cmluZywgIlteLF0rLCBcXGR7MSwyfSwgKG1hbGV8ZmVtYWxlKSIpW1sxXV0KICAgIHJldHVybihtYXBfZGYocGVvcGxlLCB+IG11dGF0ZShyb3dfZGF0YSwgdmljdGltcyA9IC54KSkpCiAgfQogIAogICMgQ2FzZSAyOiB2YWd1ZSB3aXRoIG51bWJlcgogIG51bWJlcl9tYXRjaCA8LSBzdHJfbWF0Y2godmljdGltX3N0cmluZywgIihcXGQrKXwoW1R0XXdvfFtUdF1ocmVlfFtGZl1vdXJ8W0ZmXWl2ZXxbU3NdaXh8W1NzXWV2ZW58W0VlXWlnaHQpIikKICBpZiAoIWlzLm5hKG51bWJlcl9tYXRjaFsxXSkpIHsKICAgIG51bSA8LSBzdXBwcmVzc1dhcm5pbmdzKGFzLm51bWVyaWMobnVtYmVyX21hdGNoWzFdKSkKICAgIGlmIChpcy5uYShudW0pKSB7CiAgICAgIG51bSA8LSBjYXNlX3doZW4oCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJ0d28iLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDIsCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJ0aHJlZSIsIGlnbm9yZV9jYXNlID0gVFJVRSkpIH4gMywKICAgICAgICBzdHJfZGV0ZWN0KG51bWJlcl9tYXRjaFsxXSwgcmVnZXgoImZvdXIiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDQsCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJmaXZlIiwgaWdub3JlX2Nhc2UgPSBUUlVFKSkgfiA1LAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgic2l4IiwgaWdub3JlX2Nhc2UgPSBUUlVFKSkgfiA2LAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgic2V2ZW4iLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDcsCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJlaWdodCIsIGlnbm9yZV9jYXNlID0gVFJVRSkpIH4gOCwKICAgICAgICBzdHJfZGV0ZWN0KG51bWJlcl9tYXRjaFsxXSwgcmVnZXgoImVpZ2h0IiwgaWdub3JlX2Nhc2UgPSBUUlVFKSkgfiA5LAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgiZWlnaHQiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDEwLAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgiZWlnaHQiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDExLAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgiZWlnaHQiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDEyLAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgiZWlnaHQiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDEzLAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgiZWlnaHQiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDE0LAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgiZWlnaHQiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDE1LAogICAgICAgIFRSVUUgfiAxCiAgICAgICkKICAgIH0KICAgIHJldHVybihtYXBfZGYoMTpudW0sIH4gbXV0YXRlKHJvd19kYXRhLCB2aWN0aW1zID0gIlVua25vd24iKSkpCiAgfQogIAogICMgRGVmYXVsdDogcmV0dXJuIG9yaWdpbmFsIHJvdwogIHJldHVybihyb3dfZGF0YSkKfQoKIyBBcHBseSB0byBlYWNoIHJvdwpjbGVhbmVkX2RmIDwtIGRmICU+JQogIHJvd3dpc2UoKSAlPiUKICBkbyhleHBhbmRfdmljdGltcyguJHZpY3RpbXMsIC4pKSAlPiUKICB1bmdyb3VwKCkKCiMgRmlyc3QgZXh0cmFjdCB0aGUgY291bnRyeQpjbGVhbmVkX2RmIDwtIGNsZWFuZWRfZGYgJT4lCiAgbXV0YXRlKGNvdW50cnkgPSBzdHJfZXh0cmFjdChsb2NhdGlvbiwgIlteLF0rJCIpICU+JSBzdHJfdHJpbSgpKQoKIyBUaGVuIHJlbW92ZSBhbnkgdHJhaWxpbmcgcGVyaW9kcwpjbGVhbmVkX2RmIDwtIGNsZWFuZWRfZGYgJT4lCiAgbXV0YXRlKGNvdW50cnkgPSBzdHJfcmVtb3ZlKGNvdW50cnksICJcXC4kIikpCgpjbGVhbmVkX2RmICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjb3VudHJ5LCBmaWxsID0gdHlwZV9vZl9hdHRhY2spKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgY29vcmRfZmxpcCgpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKyAgCiAgbGFicyh0aXRsZSA9ICJBdHRhY2tzIGFuZCBDb3VudHJ5IiwKICAgICAgIHggPSAiQ291bnRyeSIsCiAgICAgICB5ID0gIkNvdW50IG9mIEF0dGFja3MiKSArCiAgdGhlbWVfbWluaW1hbCgpKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpICAKCgpgYGAKCmBgYHtyLCBvdXQud2lkdGg9IjEwMCUiLCBvdXQuaGVpZ2h0PSIxMDAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIm1lZGlhL1NlY29uZF9BdHRlbXB0LnBuZyIpCmBgYAoKCiMgKipDbGVhbmVyIFdvbGYgRGF0YSoqCgpgYGB7ciwgZWNobz1UUlVFfQojIExvYWQgYW5kIGNsZWFuIHRoZSBkYXRhc2V0CmRmIDwtIHJlYWRfY3N2KCJwcmVkYXRvcnMvZ2xvYmFsX3dvbHZlcy5jc3YiKSAlPiUgCiAgY2xlYW5fbmFtZXMoKQoKIyBGdW5jdGlvbiB0byBleHBhbmQgdmljdGltcyBhbmQgZXh0cmFjdCBhZ2UgJiBzZXgKZXhwYW5kX3ZpY3RpbXMgPC0gZnVuY3Rpb24odmljdGltX3N0cmluZywgcm93X2RhdGEpIHsKICByb3dfZGF0YSA8LSBhc190aWJibGUocm93X2RhdGEpICAKICAKICB2aWN0aW1fc3RyaW5nIDwtIHN0cl9yZXBsYWNlX2FsbCh2aWN0aW1fc3RyaW5nLCAiKG1hbGV8ZmVtYWxlKSg/PVtBLVpdKSIsICJcXDE7ICIpCgogIGlmIChzdHJfZGV0ZWN0KHZpY3RpbV9zdHJpbmcsICJbQS1aYS16XSssPyA/XFxkezEsMn0sIChtYWxlfGZlbWFsZSkiKSkgewogICAgcGVvcGxlIDwtIHN0cl9leHRyYWN0X2FsbCh2aWN0aW1fc3RyaW5nLCAiW14sO10rLD8gP1xcZHsxLDJ9LCAobWFsZXxmZW1hbGUpIilbWzFdXQogICAgCiAgICByZXR1cm4obWFwX2RmKHBlb3BsZSwgZnVuY3Rpb24ocGVyc29uKSB7CiAgICAgIGFnZSA8LSBzdHJfZXh0cmFjdChwZXJzb24sICJcXGR7MSwyfSIpICU+JSBhcy5udW1lcmljKCkKICAgICAgc2V4IDwtIHN0cl9leHRyYWN0KHBlcnNvbiwgIm1hbGV8ZmVtYWxlIikKICAgICAgbXV0YXRlKHJvd19kYXRhLCB2aWN0aW1zID0gcGVyc29uLCBhZ2UgPSBhZ2UsIHNleCA9IHNleCkKICAgIH0pKQogIH0KCiAgbnVtYmVyX21hdGNoIDwtIHN0cl9tYXRjaCh2aWN0aW1fc3RyaW5nLCAiKFxcZCspfChbVHRdd298W1R0XWhyZWV8W0ZmXW91cnxbRmZdaXZlfFtTc11peHxbU3NdZXZlbnxbRWVdaWdodHxbTm5daW5lfFtUdF1lbnxbRWVdbGV2ZW58W1R0XXdlbHZlfFtUdF1oaXJ0ZWVufFtGZl1vdXJ0ZWVufFtGZl1pZnRlZW4pIikKICAKICBpZiAoIWlzLm5hKG51bWJlcl9tYXRjaFsxXSkpIHsKICAgIG51bSA8LSBzdXBwcmVzc1dhcm5pbmdzKGFzLm51bWVyaWMobnVtYmVyX21hdGNoWzFdKSkKICAgIGlmIChpcy5uYShudW0pKSB7CiAgICAgIG51bSA8LSBjYXNlX3doZW4oCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJ0d28iLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDIsCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJ0aHJlZSIsIGlnbm9yZV9jYXNlID0gVFJVRSkpIH4gMywKICAgICAgICBzdHJfZGV0ZWN0KG51bWJlcl9tYXRjaFsxXSwgcmVnZXgoImZvdXIiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDQsCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJmaXZlIiwgaWdub3JlX2Nhc2UgPSBUUlVFKSkgfiA1LAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgic2l4IiwgaWdub3JlX2Nhc2UgPSBUUlVFKSkgfiA2LAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgic2V2ZW4iLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDcsCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJlaWdodCIsIGlnbm9yZV9jYXNlID0gVFJVRSkpIH4gOCwKICAgICAgICBzdHJfZGV0ZWN0KG51bWJlcl9tYXRjaFsxXSwgcmVnZXgoIm5pbmUiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDksCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJ0ZW4iLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSB+IDEwLAogICAgICAgIHN0cl9kZXRlY3QobnVtYmVyX21hdGNoWzFdLCByZWdleCgiZWxldmVuIiwgaWdub3JlX2Nhc2UgPSBUUlVFKSkgfiAxMSwKICAgICAgICBzdHJfZGV0ZWN0KG51bWJlcl9tYXRjaFsxXSwgcmVnZXgoInR3ZWx2ZSIsIGlnbm9yZV9jYXNlID0gVFJVRSkpIH4gMTIsCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJ0aGlydGVlbiIsIGlnbm9yZV9jYXNlID0gVFJVRSkpIH4gMTMsCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJmb3VydGVlbiIsIGlnbm9yZV9jYXNlID0gVFJVRSkpIH4gMTQsCiAgICAgICAgc3RyX2RldGVjdChudW1iZXJfbWF0Y2hbMV0sIHJlZ2V4KCJmaWZ0ZWVuIiwgaWdub3JlX2Nhc2UgPSBUUlVFKSkgfiAxNSwKICAgICAgICBUUlVFIH4gMQogICAgICApCiAgICB9CiAgICAKICAgIHJldHVybihtYXBfZGYoMTpudW0sIH4gbXV0YXRlKHJvd19kYXRhLCB2aWN0aW1zID0gIlVua25vd24iLCBhZ2UgPSBOQSwgc2V4ID0gTkEpKSkKICB9CgogIHNleCA8LSBzdHJfZXh0cmFjdCh2aWN0aW1fc3RyaW5nLCAibWFsZXxmZW1hbGUiKQogIGFnZSA8LSBzdHJfZXh0cmFjdCh2aWN0aW1fc3RyaW5nLCAiXFxkezEsMn0iKSAlPiUgYXMubnVtZXJpYygpCiAgCiAgcmV0dXJuKG11dGF0ZShyb3dfZGF0YSwgdmljdGltcyA9IHZpY3RpbV9zdHJpbmcsIGFnZSA9IGFnZSwgc2V4ID0gc2V4KSkKfQoKIyBFeHBhbmQgdmljdGltcyBpbnRvIGluZGl2aWR1YWwgcm93cwpjbGVhbmVkX2RmIDwtIGRmICU+JQogIHJvd3dpc2UoKSAlPiUKICBkbyhleHBhbmRfdmljdGltcyguJHZpY3RpbXMsIC4pKSAlPiUKICB1bmdyb3VwKCkKCiMgQ2xlYW4gY291bnRyeSBpbmZvIGZyb20gJ2xvY2F0aW9uJyBjb2x1bW4KY2xlYW5lZF9kZiA8LSBjbGVhbmVkX2RmICU+JQogIG11dGF0ZSgKICAgIGNvdW50cnkgPSBzdHJfZXh0cmFjdChsb2NhdGlvbiwgIlteLF0rJCIpICU+JSBzdHJfdHJpbSgpLAogICAgY291bnRyeSA9IHN0cl9yZW1vdmUoY291bnRyeSwgIlxcLiIpCiAgKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGNvdW50cnkpICYgY291bnRyeSAhPSAiIikKCiMgR2V0IHRvcCAxNSBjb3VudHJpZXMgYnkgbnVtYmVyIG9mIGF0dGFja3MKdG9wX2NvdW50cmllcyA8LSBjbGVhbmVkX2RmICU+JQogIGNvdW50KGNvdW50cnksIHNvcnQgPSBUUlVFKSAlPiUKICBzbGljZV9oZWFkKG4gPSAxNSkgJT4lCiAgcHVsbChjb3VudHJ5KQoKIyBGaWx0ZXIgdG8ganVzdCB0aG9zZSBjb3VudHJpZXMKZmlsdGVyZWRfZGYgPC0gY2xlYW5lZF9kZiAlPiUKICBmaWx0ZXIoY291bnRyeSAlaW4lIHRvcF9jb3VudHJpZXMpCgpmaWx0ZXJlZF9kZiA8LSBmaWx0ZXJlZF9kZiAlPiUKICBmaWx0ZXIoIWlzLm5hKHR5cGVfb2ZfYXR0YWNrKSAmIHR5cGVfb2ZfYXR0YWNrICE9ICIiKQoKIyBQbG90CmZpbHRlcmVkX2RmICU+JQogIGdncGxvdChhZXMoeCA9IGZjdF9pbmZyZXEoY291bnRyeSksIGZpbGwgPSB0eXBlX29mX2F0dGFjaykpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicygKICAgIHRpdGxlID0gIlRvcCAxNSBDb3VudHJpZXMgd2l0aCBXb2xmIEF0dGFja3MiLAogICAgeCA9ICJDb3VudHJ5IiwKICAgIHkgPSAiTnVtYmVyIG9mIEF0dGFja3MiLAogICAgZmlsbCA9ICJBdHRhY2sgVHlwZSIKICApICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxOCksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkKICApCgpgYGAKCgoKQWZ0ZXIgY2xlYW5pbmcgdGhlIGRhdGEsIHlvdSBjYW4gc2VlLCBSdXNzaWEgYW5kIEZyYW5jZSBib3RoIGhhdmUgbWFueSBhdHRhY2tzLgoKCiMgKipXaG8gaXMgS2luZz8qKgoKYGBge3IsIGVjaG89VFJVRX0KCiMgMS4gU3VtbWFyaXplIHRoZSBudW1iZXIgb2YgYXR0YWNrcyBmcm9tIGVhY2ggY2xlYW5lZCBkYXRhc2V0CgojIEFsbGlnYXRvcgpnYXRvcl9hdHRhY2tzIDwtIGdhdG9yICU+JQogIGZpbHRlcighaXMubmEoZGF0ZSkpICU+JQogIG5yb3coKQoKIyBTaGFyayAtIFVzaW5nIHNoYXJrXzEgc2luY2UgaXQgaGFzIG1vc3Qgcm93cyBhbmQgd2FzIHByZS1jbGVhbmVkCnNoYXJrX2F0dGFja3MgPC0gc2hhcmtfMSAlPiUKICBmaWx0ZXIoIWlzLm5hKHR5cGUpLCB0eXBlICE9ICJVbmtub3duIikgJT4lCiAgbnJvdygpCgojIFdvbHZlcyAtIFVzaW5nIGNsZWFuZWRfZGYgZnJvbSB3b2xmIGRhdGEKd29sZl9hdHRhY2tzIDwtIGNsZWFuZWRfZGYgJT4lCiAgZmlsdGVyKCFpcy5uYSh0eXBlX29mX2F0dGFjayksIHR5cGVfb2ZfYXR0YWNrICE9ICIiKSAlPiUKICBucm93KCkKCiMgMi4gQ3JlYXRlIGEgY29tcGFyaXNvbiBkYXRhIGZyYW1lCmF0dGFja19raW5nX2RmIDwtIHRpYmJsZSgKICBwcmVkYXRvciA9IGMoIlNoYXJrIiwgIkFsbGlnYXRvciIsICJXb2xmIiksCiAgdG90YWxfYXR0YWNrcyA9IGMoc2hhcmtfYXR0YWNrcywgZ2F0b3JfYXR0YWNrcywgd29sZl9hdHRhY2tzKQopCgojIDMuIFBsb3QgaXQKYXR0YWNrX2tpbmdfZGYgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihwcmVkYXRvciwgdG90YWxfYXR0YWNrcyksIHkgPSB0b3RhbF9hdHRhY2tzLCBmaWxsID0gcHJlZGF0b3IpKSArCiAgZ2VvbV9jb2wod2lkdGggPSAwLjYpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdG90YWxfYXR0YWNrcyksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDQpICsKICBsYWJzKAogICAgdGl0bGUgPSAiVGhlIEtpbmcgb2YgQXR0YWNrcyIsCiAgICB4ID0gIlByZWRhdG9yIiwKICAgIHkgPSAiRG9jdW1lbnRlZCBBdHRhY2tzIgogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlNoYXJrIiA9ICIjRkYzQzM4IiwgIkFsbGlnYXRvciIgPSAiIzBDOTQ2MyIsICJXb2xmIiA9ICIjNEM0QzZEIikpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE2KSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMjApLAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiCiAgKQoKYGBgCgoKCgojICoqTG9uZyBMaXZlIEtpbmcgSmF3cyoqCgpUaGUgS2luZyBvZiBhdHRhY2tzIGlzIHRoZSBzaGFyay4gVGhlIGRhdGEgc2hvd3MgdGhhdCBzaGFya3MgaGF2ZSB0aGUgbW9zdCBhdHRhY2tzLiBMb29rIGF0IHRoZSBtYXAgb2YgQXVzdHJhbGlhIGFnYWluLCBldmVyeSBtYXJrZXIgaXMgd2hlcmUgYSBzaGFyayBhdHRhY2sgaGFzIG9jY3VycmVkLiBBbHNvLCBhbm90aGVyIHJlYXNvbiB3aHkgdGhlIHNoYXJrIGRhdGEgaXMga2luZyBpcyBkdWUgdG8gYSBsYWNrIGFuZCBtaXNzaW5nIGRhdGEgZnJvbSBib3RoIHRoZSB3b2x2ZXMgYW5kIGdhdG9ycy4gSWYgdGhlcmUgd2FzIGRhdGEgZm9yIE5pbGUgQ3JvY3MsIHRoZXJlIG1pZ2h0IGJlIHNvbWUgY29tcGV0aXRpb24uIAoKCmBgYHtyLCBvdXQud2lkdGg9IjcwJSIsIG91dC5oZWlnaHQ9IjcwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJtZWRpYS9zaGFyay5wbmciKQpgYGAKClBpY3R1cmUgZnJvbSBbYnJpdGFubmljYV0oaHR0cHM6Ly93d3cuYnJpdGFubmljYS5jb20vYW5pbWFsL3NoYXJrKQoKCiMgKipUb3VyIEd1aWRlIFRpcHMqKgoKV2hlbiB2aXNpdGluZyBGbG9yaWRhIG9yIEF1c3RyYWxpYSwgd2F0Y2ggeW91ciBmZWV0IGFuZCBzdXJyb3VuZGluZ3MuIEluIEZsb3JpZGEsIHByZXR0eSBtdWNoIGV2ZXJ5dGhpbmcgd2FudHMgdG8gZWF0IHlvdSBmcm9tIGJ1Z3MgdG8gQWxsaWdhdG9ycy9Dcm9jcywgc25ha2VzLCBzaGFya3MsIGV0Yy4gSXQgaXMgYSBkYW5nZXJvdXMgYW5kIHdvbmRlcmZ1bCBwbGFjZSwgYXMgbG9uZyBhcywgeW91IGFyZSBjYXJlZnVsLiBCZXNpZGVzLCBhbGwgdGhlIHRoaW5ncyB0aGF0IGFyZSB3YW50aW5nIHRvIGVhdCB5b3UuLi5tYWtlIGZvciBhIHRhc3R5IG1lYWwgb24geW91ciBkaW5uZXIgcGxhdGUgaW4gdGhlIGVuZC4gSSB3YW50IHRvIHJldHVybiB0byBGbG9yaWRhIHRvIGdldCBzb21lIGNyb2MvZ2F0b3IgbWVhdC4gU2hhcmsgaXMgbm90IGJhZCwgaXQgaXMganVzdCBhIGZpc2h5LCBjaGV3eSBtZWF0LiAKCkF1c3RyYWxpYSBoYXMgYSBsYXJnZXIgdmFyaWV0eSBvZiBkYW5nZXJzLCBhIGxvdCBvZiBzaGFyayBhdHRhY2tzLCBwb2lzb25vdXMgc25ha2VzLCBqZWxseWZpc2gsIGNyb2NzLCBhbmQgb3RoZXIgZGFuZ2Vycy4gUEJTIGhhcyBiZWVuIG15IGd1aWRlIHRvIEF1c3RyYWxpYS4gCgojICoqTWFpbiBQb2ludHM6KioKCjEtIERvIG5vdCB1bmRlcmVzdGltYXRlIGEgcHJlZGF0b3IgYnkgdGhpbmtpbmcgdGhleSBhcmUgc2xvdwoKMi0gV2F0Y2ggeW91ciBzdXJyb3VuZGluZ3MKCjMtIEJlIGNhcmVmdWwgd2hlbiBnb2luZyBuZWFyIGFueSB3YXRlciBzb3VyY2UKCjQtIERvbid0IHByb3Zva2UgdGhlIHdpbGRsaWZlCgo1LSBEbyBub3QgZmVlZCB0aGUgd2lsZGxpZmUKCjYtIERvIG5vdCBnZXQgY2xvc2UgdG8gdGhlIHdpbGRsaWZlIChQb3RlbnRpYWwgRGVhdGggUmlzaykKCjctIElmIHlvdSBhcmUgc3R1bmcgYnkgYSBqZWxseWZpc2ggcmluc2UgdGhlIGFyZWEgd2l0aCB3YXRlciwgZG8gbm90IHVyaW5hdGUgb24gaXQKCjgtIElmIHlvdSBhcmUgYml0LCAoZGVwZW5kaW5nIG9uIHdoYXQgYml0IHlvdSBhbmQgd2hlcmUgeW91IGFyZSBiaXQpIGlmIHlvdSBoYXZlIGEgd2VhcG9uLCBmaWdodCBiYWNrLiAKCldpdGggY3JvY3MgYW5kIGdhdG9yczogZXllcywgbm9zZSwgb3IgdGhyb2F0IGFyZSByZWNvbW1lbmRlZCB0byBzdGFiIGF0LiBJZiBpdCBpcyBhIHNuYWtlIG9yIGEgaW5zZWN0IGdldCBoZWxwLCBhcyBzb29uIGFzIHBvc3NpYmxlLiAKCklmIHlvdSBhcmUgYml0IGJ5IGEgZ2F0b3IvY3JvYywgc2hhcmssIHNuYWtlcywgYW50cywgc3BpZGVycywgb3IgYW55IHNvcnQgb2Ygd2lsZGxpZmUgZ2V0IGhlbHAgQVNBUCwgeW91IGNhbiBwb3RlbnRpYWxseSBkaWUgZnJvbSBhIGJhY3RlcmlhbCBpbmZlY3Rpb24gb3IgcmFiaWVzLiAKClNvbWUgc25ha2VzIGluIEZsb3JpZGEgKGNvdHRvbm1vdXRoIHNuYWtlKSBhcmUganVzdCBuYXN0eSBhbmQgaGF2ZSBhIGJhZCBiYWN0ZXJpYSBpbiB0aGVpciBtb3V0aCB0aGF0IHdpbGwgY2F1c2UgZ2FuZ3JlbmUuIAoKCiMgKipIb25vcmFibGUgTWVudGlvbnMqKgoKMS0gR29sZGVuIExhYnMKCjItIEJpcmRzCgozLSBKZWxseWZpc2gKCjQtIEV0Yy4g